home *** CD-ROM | disk | FTP | other *** search
/ PsL Monthly 1993 December / PSL Monthly Shareware CD-ROM (December 1993).iso / prgmming / dos / pascal / baseapp.exe / BAPP10.PAS < prev    next >
Encoding:
Pascal/Delphi Source File  |  1991-09-15  |  16.1 KB  |  437 lines

  1. PROGRAM BasicApp;
  2.  
  3. {(c) 1991 John C. Leon}
  4.  
  5. {Version 1.0   9/15/91}
  6.  
  7. {READ THESE COMMENTS BEFORE USING THIS CODE!}
  8.  
  9. {This base application was prepared for my personal use, as I do not wish
  10.  to recreate the wheel with each new TV application.  Because I seem to
  11.  always want the same skeleton in my TV apps, this base set of code has become
  12.  very helpful!
  13.  
  14.  Included in the base app is code for properly handling window numbers,
  15.  enabling a video mode toggle, providing tileable/cascadable windows,
  16.  testing for application-specific conditions before presenting the main
  17.  menu (and showing error message windows if there's a problem), and generating
  18.  a title screen on initialization.
  19.  
  20.  All windows should be descendants of BWindow.  Your descendants can
  21.  freely modify BWindow.Init and BWindow.Done.  As long as they call
  22.  BWindow.Init and BWindow.Done, you can assure yourself that they will
  23.  be tilable/cascadable, and that window numbers will be properly handled.
  24.  
  25.  The BaseApp.BaseWindow procedure opens an empty, generic window.  This is
  26.  provided only so that you can see the use of the SetWinCount procedure, and
  27.  so that you can see properly working window numbers.  To test it out, open
  28.  a few windows.  Then close, say, window #2.  Open a new window, and it will
  29.  use #2 (the first available window number).  If only something as basic as
  30.  this was built into TV, eh?
  31.  
  32.  A generic menubar and statusline are provided, including help contexts.  This
  33.  will be extremely helpful for programmers struggling with how to implement
  34.  help contexts, if like me, you lost a lot of sleep getting it right the
  35.  first time!
  36.  
  37.  The base app also includes code to put up a message box if the application
  38.  fails to initialize.  That is, if you require certain conditions to be met
  39.  before your user can even start the app (data files must be present, etc)
  40.  you can initialize TV anyway and use a message box to state the cause of
  41.  failure.  For this reason, the base application uses the TVision sample unit
  42.  MSGBOX (a VERY useful set of routines!).  To illustrate how this works, THE
  43.  BASE APP REQUIRES THAT THE SOURCE CODE FILE (or any file named BASEAPP.PAS)
  44.  BE PRESENT IN THE CURRENT DIRECTORY.
  45.  
  46.  If you find this code helpful, I'd appreciate a whopping $10.  This'll buy
  47.  you copies of any future utilities, versions, etc, and the legal right to
  48.  use this software.  This is SHAREWARE, folks, *NOT* freeware or public
  49.  domain.  Act accordingly.
  50.  
  51.  Constructive criticism and suggestions always welcome.
  52.  
  53.  John C. Leon
  54.  3807 Wood Gardens Court
  55.  Kingwood, TX  77339
  56.  
  57.  CIS 72426,2077
  58.  
  59.  N.B.  The ColBackground routines (the code to change background color) are
  60.        taken directly from Neil J. Rubenking's book, Turbo Pascal 6.0
  61.        Techniques and Utilities...a MUST for your collection).
  62.  
  63.        Attention Btrieve programmers!  My object-oriented unit for handling
  64.        standard Btrieve files is available currently as FREEWARE.  Makes
  65.        TP6 Btrieve programming a snap!  It is available on CIS in forum
  66.        BPROGA, library 1 (OOP).  Just browse for file BTP*.ZIP
  67.        (* = version number).
  68.  
  69. }
  70.  
  71.  
  72. USES
  73.    App, Dialogs, Objects, Menus, Views, Drivers, MsgBox;
  74.  
  75.  
  76. CONST
  77.    cmSetVideoMode    = 100;
  78.    cmBaseWindow      = 110;
  79.    cmAbout           = 120;
  80.    ErrorInitializing : integer = 0;
  81.    WinCount          : integer = 0;
  82.  
  83.  
  84. TYPE
  85.    BaseApp = object(TApplication)
  86.       constructor Init;
  87.       procedure InitMenuBar   ; virtual;
  88.       procedure InitStatusLine; virtual;
  89.       procedure TitleScreen;
  90.       procedure TileAll;
  91.       procedure CascadeAll;
  92.       procedure SetVideoMode;
  93.       procedure BaseWindow;
  94.       procedure HandleEvent(var Event: TEvent); virtual;
  95.       destructor Done; virtual;
  96.       end;
  97.  
  98.    PColBackground   = ^ColBackground;
  99.    ColBackground    = object(TBackground)
  100.                       Color: Byte;
  101.                       constructor Init(var Bounds: TRect; APat: Char;
  102.                                        AColor: Byte);
  103.                       procedure Draw; virtual;
  104.                       end;
  105.  
  106.    PHelpStatusLine  = ^THelpStatusLine;
  107.    THelpStatusLine  = object(TStatusLine)
  108.                       function Hint(AHelpCtx: Word): string; virtual;
  109.                       end;
  110.  
  111.    PWindow       = ^BWindow;
  112.    BWindow       =  object(TWindow)
  113.                     constructor Init(var Bounds: TRect; WinTitle: string;
  114.                                      WinNumber: integer);
  115.                     destructor Done; virtual;
  116.                     end;
  117.  
  118.  
  119. VAR
  120.    BApp                : BaseApp;
  121.    WinNumberCollection : PStringCollection; {initialized during BaseApp.Init}
  122.    WinNumberString     : string;
  123.    RequiredFile        : text;  {NOT required for basic app, but is used as
  124.                                  an illustration of message box use if app's
  125.                                  required files/conditions are not met and
  126.                                  you DON'T want user to 'enter' application.}
  127.  
  128. constructor BaseApp.Init;
  129. var
  130.    R      : TRect;
  131.    Counter: integer;
  132.    Control: word;
  133. begin
  134.    {Set up the collection of window numbers, sorted automatically from 1 to 9.}
  135.    WinNumberCollection := New(PStringCollection, Init(9,0));
  136.    for Counter := 1 to 9 do
  137.       begin
  138.       str(Counter,WinNumberString);
  139.       WinNumberCollection^.Insert(NewStr(WinNumberString));
  140.       end;
  141.  
  142.   {NOTE: The variable 'ErrorInitializing' MUST be assigned before calling
  143.    TApplication.Init, as TApplication.Init will internally initialize the
  144.    menu and status line.  The base application's overrides of InitMenuBar and
  145.    InitStatusLine depend on ErrorInitializing being assigned.  This location
  146.    in the BaseApp.Init is where you'd put your various app initialization
  147.    tests.  See the case statement below for actions to take on failure of
  148.    your initializations.}
  149.    assign(RequiredFile,'BaseApp.Pas');
  150.    {$I-} reset(RequiredFile); {$I+}
  151.    if ioresult <> 0 then
  152.       ErrorInitializing := 1;
  153.  
  154.    {Call ancestor.}
  155.    TApplication.Init;
  156.  
  157.    {Replace background with one of new color.  Credit to Neil J. Rubenking's
  158.     book, Turbo Pascal 6.0 Techniques and Utilities for this code.}
  159.    Desktop^.Background^.GetExtent(R);
  160.    Desktop^.Delete(Desktop^.Background);
  161.    Dispose(Desktop^.Background, done);
  162.    Desktop^.Background := New(PColBackground, Init(R, #176, 9));
  163.    Desktop^.Insert(Desktop^.Background);
  164.  
  165.    {No windows open at initialization, so disable the Tile and Cascade cmds
  166.     on menu.}
  167.    DisableCommands([cmTile, cmCascade]);
  168.  
  169.    {Universally turn off the Video Mode option on menu if user screen can't
  170.     handle it.}
  171.    if HiResScreen = false then
  172.      DisableCommands([cmSetVideoMode]);
  173.  
  174.    {Put up a generic title screen.  Note what's done if there's an error
  175.     initializing your app.  Expand this case statement as required to put
  176.     up different messages depending on which of you application's requirements
  177.     was not met.}
  178.    case ErrorInitializing of
  179.       0: TitleScreen;
  180.       1: Control := MessageBox(^C'Required file not found'^M^C'Cannot run Base App',
  181.                                 nil, mfError + mfOKButton);
  182.       end;
  183. end;
  184.  
  185. destructor BaseApp.Done;
  186. begin
  187.    TApplication.Done;
  188.    dispose(WinNumberCollection, Done); {Call this AFTER calling ancestor!}
  189. end;
  190.  
  191. procedure SetWinCount;
  192. function GetWinCount(WString: PString): boolean; far;
  193.    begin
  194.    GetWinCount := WString <> nil;  {effectively sets position to first}
  195.    end;                            {*available* window number!        }
  196. var
  197.    Code            : integer;
  198.    PWinNumber      : pointer;
  199. begin
  200.    if WinNumberCollection^.Count = 0 then {if #'s 1 thru 9 have been used}
  201.          WinCount := wnNoNumber
  202.       else
  203.          begin
  204.          PWinNumber := WinNumberCollection^.FirstThat(@GetWinCount);
  205.          WinNumberString := string(PWinNumber^);
  206.          val(WinNumberString, WinCount, Code);
  207.          WinNumberCollection^.Delete(PWinNumber);
  208.          disposestr(PWinNumber);
  209.          end;
  210. end;
  211.  
  212. constructor ColBackground.Init(var Bounds: TRect; APat: Char; AColor: Byte);
  213. begin
  214.    TBackground.Init(Bounds, APat);
  215.    Color := AColor;
  216. end;
  217.  
  218. procedure ColBackground.Draw;
  219. var
  220.    B: TDrawBuffer;
  221. begin
  222.    fillchar(B, SizeOf(B),0);
  223.    movechar(B, Pattern, Color, Size.X);
  224.    writeline(0,0,Size.X,Size.Y,B);
  225. end;
  226.  
  227. procedure BaseApp.TitleScreen;
  228. var
  229.    Dialog  : PDialog;
  230.    R       : TRect;
  231.    Control : Word;
  232. begin
  233.    R.Assign(0,5,33,13);  {Can use origin point of 0 as we are going to set
  234.                           Options to center the dialog anyway!}
  235.    Dialog := New(PDialog, Init(R, 'Title Screen'));
  236.    with Dialog^ do
  237.       begin
  238.       Flags := Flags and not wfMove;     {don't make title screen movable}
  239.       Options := Options or ofCentered;  {center it in any video mode    }
  240.       R.Assign(1, 2, 32, 3);
  241.       Insert(New(PStaticText, Init(R, ^C'Base App V1.0')));
  242.       R.Assign(1, 3, 32, 4);
  243.       Insert(New(PStaticText, Init(R, ^C'(C) 1991 John C. Leon')));
  244.       R.Assign(12, 5, 20, 7);
  245.       Insert(New(PButton, Init(R, ' OK', cmCancel, bfNormal)));
  246.       end;
  247.    Control := Desktop^.ExecView(Dialog);
  248.    dispose(Dialog, Done);
  249. end;
  250.  
  251. procedure BaseApp.InitMenuBar;
  252. {Help context numbers 0-999 reserved by TVision.  I opt to reserve 1000 for
  253.  some unknown future use!}
  254. var R: TRect;
  255. begin
  256.   GetExtent(R);
  257.   R.B.Y := R.A.Y + 1;
  258.   if ErrorInitializing > 0 then
  259.      MenuBar := New(PMenuBar, Init(R, NewMenu(NewItem('', '', kbNoKey,
  260.                      cmQuit, hcNoContext, nil))))
  261.      else
  262.      MenuBar := New(PMenuBar, Init(R, NewMenu(
  263.        NewSubMenu('~F~ile', 1001, NewMenu(
  264.          NewItem('~B~ase Window', 'F3', kbF3, cmBaseWindow, 1002,
  265.          NewLine(
  266.          NewItem('E~x~it', 'Alt-X', kbAltX, cmQuit, 1003,
  267.          nil)))),
  268.       NewSubMenu('~W~indow', 1050, NewMenu(
  269.          NewItem('~S~ize/Move', 'Ctrl-F5', kbCtrlF5, cmResize, 1051,
  270.          NewItem('~Z~oom', 'F5', kbF5, cmZoom, 1052,
  271.          NewItem('~T~ile', '', kbNoKey, cmTile, 1053,
  272.          NewItem('C~a~scade', '', kbNoKey, cmCascade, 1054,
  273.          NewItem('~N~ext', 'F6', kbF6, cmNext, 1055,
  274.          NewItem('~P~revious', 'Shift-F6', kbShiftF6, cmPrev, 1056,
  275.          NewItem('~C~lose', 'Alt-F3', kbAltF3, cmClose, 1057,
  276.          nil)))))))),
  277.       NewSubMenu('~O~ptions', 1060, NewMenu(
  278.          NewItem('~V~ideo Mode', '', kbNoKey, cmSetVideoMode, 1061,
  279.          nil)),
  280.       NewSubMenu('~H~elp', 1070, NewMenu(
  281.          NewItem('~A~bout...', 'F10', kbF10, cmAbout, 1071, nil)),
  282.       nil))
  283.       )))));
  284. end;
  285.  
  286. procedure BaseApp.InitStatusLine;
  287. var R:TRect;
  288. begin
  289.    GetExtent(R);
  290.    R.A.Y := R.B.Y - 1;
  291.    if ErrorInitializing > 0 then
  292.       StatusLine := New(PHelpStatusLine, Init(R, NewStatusDef(0, $FFFF,
  293.                         NewStatusKey('~Alt-X~ Exit', kbAltX, cmQuit, nil),
  294.                         nil)))
  295.       else
  296.       StatusLine := New(PHelpStatusLine, Init(R,
  297.                         NewStatusDef(0, 1000,
  298.                            NewStatusKey('~F1~ Help', kbF1, cmHelp,
  299.                            NewStatusKey('~F10~ Menu', kbF10, cmMenu,
  300.                            NewStatusKey('~Alt-X~ Exit', kbAltX, cmQuit,
  301.                            NewStatusKey('~Alt-F3~ Close', kbAltF3, cmClose,
  302.                            nil)))),
  303.                         NewStatusDef(1001, 1009,
  304.                            NewStatusKey('~File~', kbNoKey, cmHelp,
  305.                            NewStatusKey('', kbF10, cmMenu,
  306.                            NewStatusKey('', kbAltF3, cmClose,
  307.                            nil))),
  308.                         NewStatusDef(1050, 1059,
  309.                            NewStatusKey('~Window Controls~', kbNoKey, cmHelp,
  310.                            NewStatusKey('', kbF10, cmMenu,
  311.                            NewStatusKey('', kbAltF3, cmClose,
  312.                            nil))),
  313.                         NewStatusDef(1060, 1069,
  314.                            NewStatusKey('~System Options~', kbNoKey, cmHelp,
  315.                            NewStatusKey('', kbF10, cmMenu,
  316.                            NewStatusKey('', kbAltF3, cmClose,
  317.                            nil))),
  318.                         NewStatusDef(1070, 1079,
  319.                            NewStatusKey('~F1~ Help', kbF1, cmHelp,
  320.                            NewStatusKey('', kbF10, cmMenu,
  321.                            NewStatusKey('', kbAltF3, cmClose,
  322.                            nil))),
  323.                         NewStatusDef(1080, $FFFF,
  324.                            NewStatusKey('~F1~ Help', kbF1, cmHelp,
  325.                            NewStatusKey('~F10~ Menu', kbF10, cmMenu,
  326.                            NewStatusKey('~Alt-X~ Exit', kbAltX, cmQuit,
  327.                            NewStatusKey('~Alt-F3~ Close', kbAltF3, cmClose,
  328.                            nil)))),
  329.                         nil))))))));
  330. end;
  331.  
  332. function THelpStatusLine.Hint(AHelpCtx: word): string;
  333. begin
  334.    case AHelpCtx of
  335.       1001: Hint := 'Base App File Functions';
  336.       1002: Hint := 'Open Base Window';
  337.       1003: Hint := 'Quit Base Application';
  338.       1050: Hint := 'Open, arrange and move between windows';
  339.       1051: Hint := 'Change the size or position of the active window';
  340.       1052: Hint := 'Enlarge or restore the size of the active window';
  341.       1053: Hint := 'Arrange windows on desktop by tiling';
  342.       1054: Hint := 'Arrange windows on desktop by cascading';
  343.       1055: Hint := 'Make the next window active';
  344.       1056: Hint := 'Make the previous window active';
  345.       1057: Hint := 'Close the active window';
  346.       1060: Hint := 'Miscellaneous system options';
  347.       1061: Hint := 'For EGA/VGA only - toggle between normal and 43/50 line mode';
  348.       1070: Hint := '';
  349.       1071: Hint := 'Show title screen, version information';
  350.       1080: Hint := 'Quit Base Application';
  351.       1081: Hint := 'Close all windows and exit Base Application';
  352.    else
  353.       Hint := '';
  354.       end;
  355. end;
  356.  
  357. constructor BWindow.Init(var Bounds: TRect; WinTitle: string;
  358.                       WinNumber: integer);
  359. begin
  360.    TWindow.Init(Bounds, WinTitle, WinNumber);
  361.    Options := Options or ofTileable; {make 'em tile/cascade}
  362.    EnableCommands([cmTile, cmCascade]);
  363. end;
  364.  
  365. destructor BWindow.Done;
  366. begin
  367.    if NextView^.NextView = nil then         {If window is last on desktop,   }
  368.       DisableCommands([cmTile, cmCascade]); {then disable tile/cascade cmds. }
  369.    TWindow.Done; {must come *after* if statement above}
  370.    if Number <> wnNoNumber then {i.e. if BWindow.Number <> wnNoNumber}
  371.       begin
  372.       str(Number,WinNumberString);
  373.       WinNumberCollection^.Insert(NewStr(WinNumberString));
  374.       end;
  375. end;
  376.  
  377. procedure BaseApp.BaseWindow;
  378. var
  379.    Window: PWindow;
  380.    R: TRect;
  381. begin
  382.    GetExtent(R);   {get max dimensions of window}
  383.    R.Grow(-4, 0);  {shrink in X direction};
  384.    R.A.Y := R.A.Y + 2;  R.B.Y := R.B.Y - 4;  {shrink in Y direction}
  385.    SetWinCount;
  386.    Window := New(PWindow, Init(R, 'Base App Window', WinCount));
  387.    Desktop^.Insert(Window);
  388. end;
  389.  
  390. procedure BaseApp.HandleEvent(var Event: TEvent);
  391. begin
  392.   TApplication.HandleEvent(Event);
  393.   if Event.What = evCommand then
  394.      begin
  395.      case Event.Command of
  396.           cmAbout       : TitleScreen;
  397.           cmTile        : TileAll;
  398.           cmCascade     : CascadeAll;
  399.           cmSetVideoMode: SetVideoMode;
  400.           cmBaseWindow  : BaseWindow;
  401.        else
  402.           Exit;
  403.        end;
  404.      ClearEvent(Event);
  405.      end;
  406. end;
  407.  
  408. procedure BaseApp.TileAll; {The cmTile and cmCascade commands are disabled }
  409. var                        {at app init, are in place whenever windows are }
  410.    R: TRect;               {open, and are disabled by RepoWindow.Done if   }
  411. begin                      {the window being closed is the last on desktop.}
  412.    DeskTop^.GetExtent(R);
  413.    Desktop^.Tile(R);
  414. end;
  415.  
  416. procedure BaseApp.CascadeAll;
  417. var
  418.    R: TRect;
  419. begin
  420.    Desktop^.GetExtent(R);
  421.    Desktop^.Cascade(R);
  422. end;
  423.  
  424. procedure BaseApp.SetVideoMode;
  425. begin
  426.    {During BaseApp.Init we tested for EGA/VGA screen, and DISABLED this
  427.     cmSetVideoMode command (a toggle) for non-EGA/VGA screens.}
  428.    TApplication.SetScreenMode(ScreenMode xor smFont8x8);
  429. end;
  430.  
  431.  
  432. begin
  433.    BApp.Init;
  434.    BApp.Run;
  435.    BApp.Done;
  436. end.
  437.